package com.xsg.printer.core.conditions;

import com.xsg.printer.core.TemplateDrawHandler;
import com.xsg.printer.core.enums.AlignEnum;
import com.xsg.printer.core.enums.FloatAlignEnum;
import com.xsg.printer.core.enums.VoucherEnum;
import com.xsg.printer.core.exception.VoucherPrintException;
import com.xsg.printer.core.model.XsgFont;
import com.xsg.printer.core.model.XsgSheet;
import com.xsg.printer.core.model.XsgTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class SheetStepHelper<T> {

    public static <T> AddCellConfig<T> from(List<T> values) {
        return new SheetStepHelperBuilder<>(values);
    }

    public interface AddCellConfig<T> {

        AddCellConfig<T> column(String headerName, Function<T, String> function);

        VoucherType sheet(int width, int height, int cellWidth, int cellHeight, XsgFont font);

        default VoucherType sheet(int width, int height, int cellWidth, int cellHeight) {
            return sheet(width, height, cellWidth, cellHeight, XsgFont.defaultFont());
        }

        VoucherType sheet(int cellWidth, int cellHeight, XsgFont font);

        default VoucherType sheet(int cellWidth, int cellHeight) {
            return sheet(cellWidth, cellHeight, XsgFont.defaultFont());
        }
    }

    public interface VoucherType {
        SheetDraw type(VoucherEnum voucherEnum);
    }

    public interface SheetDraw {
        String draw();
    }

    public static class SheetStepHelperBuilder<T> implements AddCellConfig<T>, SheetDraw, VoucherType {

        private List<T> values;

        private List<SheetCellConfig<T>> cellConfigs;

        private XsgTemplate template;

        private VoucherEnum voucherEnum;

        public SheetStepHelperBuilder(List<T> values) {
            this.values = values;
            cellConfigs = new ArrayList<>();
        }

        @Override
        public AddCellConfig<T> column(String headerName, Function<T, String> function) {
            if (function == null) {
                throw new VoucherPrintException("表格生成取值函数不能为空");
            }
            SheetCellConfig<T> cellConfig = new SheetCellConfig<>();
            cellConfig.setHeaderName(headerName);
            cellConfig.setBodyFunction(function);
            cellConfigs.add(cellConfig);
            return this;
        }

        @Override
        public VoucherType sheet(int width, int height, int cellWidth, int cellHeight, XsgFont font) {
            String[] headers = cellConfigs.stream().map(SheetCellConfig::getHeaderName).toArray(String[]::new);
            template = TemplateStepConfig.builder()
                    .body(width + 100, height + 100)
                    .div(width + 100, height + 100, FloatAlignEnum.LEFT, ElementConfig.builder()
                            .sheet("value", width, height, XsgSheet.instance().setHeaders(headers).setCellWidth(cellWidth).setCellHeight(cellHeight), AlignEnum.CENTER, font)
                    .build()
            ).build();
            return this;
        }

        @Override
        public VoucherType sheet(int cellWidth, int cellHeight, XsgFont font) {
            int width = cellWidth * cellConfigs.size();
            int height = cellHeight * values.size();
            return sheet(width, height, cellWidth, cellHeight, font);
        }

        @Override
        public SheetDraw type(VoucherEnum voucherEnum) {
            this.voucherEnum = voucherEnum;
            return this;
        }

        @Override
        public String draw() {
            if (values == null || values.isEmpty() || template == null) {
                return null;
            }
            List<List<String>> rows = new ArrayList<>();
            for (T t : values) {
                List<String> row = new ArrayList<>();
                for (SheetCellConfig<T> cellConfig : cellConfigs) {
                    row.add(cellConfig.getBodyFunction().apply(t));
                }
                rows.add(row);
            }
            Map<String, Object> param = new HashMap<>();
            param.put("value", rows);
            return TemplateDrawHandler.getInstance().draw(template, voucherEnum, param);
        }
    }
}
